package com.aaron.provider.impl;

import com.aaron.config.RpcServiceConfig;
import com.aaron.enums.RpcErrorMessageEnum;
import com.aaron.exception.RpcException;
import com.aaron.extension.ExtensionLoader;
import com.aaron.provider.ServiceProvider;
import com.aaron.registry.ServiceRegistry;
import com.aaron.remoting.transport.netty.server.NettyRpcServer;
import lombok.extern.slf4j.Slf4j;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;


@Slf4j
public class ZkServiceProviderImpl implements ServiceProvider {

    // key: rpc service name(interface name + version + group)，value:服务端提供服务的接口的实现类
    private final Map<String, Object> serviceMap;
    // 保存serviceMap的key值集合
    private final Set<String> registeredService;
    // 服务注册类
    private final ServiceRegistry serviceRegistry;

    // 构造方法初始化
    public ZkServiceProviderImpl() {
        serviceMap = new ConcurrentHashMap<>();
        // keySet()方法用于从哈希映射中包含的关键元素中创建一个集合。我们可以创建一个新集合并将键元素存储在其中。
        registeredService = ConcurrentHashMap.newKeySet();
        // 获取ServiceRegistry.class接口的实现类ZkServiceRegistry。这个实例对象
        serviceRegistry = ExtensionLoader.getExtensionLoader(ServiceRegistry.class).getExtension("zk");
    }

    @Override
    public void addService(RpcServiceConfig rpcServiceConfig) {
        // rpc service name(interface name + version + group),例：com.aaron.HelloServicetest2version2
        String rpcServiceName = rpcServiceConfig.getRpcServiceName();
        // 如果这个服务名存在，就直接返回
        if (registeredService.contains(rpcServiceName)) {
            return;
        }
        // 否则先向registeredService这个Set集合中添加，再向Map<String, Object> serviceMap中添加
        registeredService.add(rpcServiceName);
        // serviceMap中保存的就是key:String类型，value：Object类型的Service对象
        serviceMap.put(rpcServiceName, rpcServiceConfig.getService());
        log.info("Add service: {} and interfaces:{}", rpcServiceName, rpcServiceConfig.getService().getClass().getInterfaces());
    }

    // 获取Service对象,Object类型的.其实就是个接口类型
    @Override
    public Object getService(String rpcServiceName) {
        // 先根据RpcServiceName从map中获取Service对象
        Object service = serviceMap.get(rpcServiceName);
        if (null == service) {
            throw new RpcException(RpcErrorMessageEnum.SERVICE_CAN_NOT_BE_FOUND);
        }
        return service;
    }

    // 发布服务，才真正将 服务地址 注册到了zk上
    @Override
    public void publishService(RpcServiceConfig rpcServiceConfig) {
        try {
            String host = InetAddress.getLocalHost().getHostAddress();
            this.addService(rpcServiceConfig);
//            Class<?> serviceRelatedInterface = service.getClass().getInterfaces()[0];
            // getCanonicalName：获取所传类从java语言规范定义的格式输出。
//            String serviceName = serviceRelatedInterface.getCanonicalName();
//            // 设置服务名
//            rpcServiceProperties.setServiceName(serviceName);
//            this.addService(service, serviceRelatedInterface, rpcServiceProperties);

            // 注册服务，NettyRpcServer.PORT=9998，将服务名和套接字地址注册到zk上，成为一个客户端
            // 调用zookeeper客户端去创建这个节点
            serviceRegistry.registerService(rpcServiceConfig.getRpcServiceName(), new InetSocketAddress(host, NettyRpcServer.PORT));
        } catch (UnknownHostException e) {
            log.error("occur exception when getHostAddress", e);
        }
    }

}
